﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

#if NET40
namespace System.Diagnostics
{
    //
    // 摘要:
    //     A DiagnosticListener is something that forwards on events written with DiagnosticSource.
    //     It is an IObservable (has Subscribe method), and it also has a Subscribe overload
    //     that lets you specify a 'IsEnabled' predicate that users of DiagnosticSource
    //     will use for 'quick checks'. The item in the stream is a KeyValuePair[string,
    //     object] where the string is the name of the diagnostic item and the object is
    //     the payload (typically an anonymous type). There may be many DiagnosticListeners
    //     in the system, but we encourage the use of The DiagnosticSource.DefaultSource
    //     which goes to the DiagnosticListener.DefaultListener. If you need to see 'everything'
    //     you can subscribe to the 'AllListeners' event that will fire for every live DiagnosticListener
    //     in the appdomain (past or present). Please See the DiagnosticSource Users Guide
    //     https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/DiagnosticSourceUsersGuide.md
    //     for instructions on its use.
    public class DiagnosticListener : DiagnosticSource, IObservable<KeyValuePair<string, object>>, IDisposable
    {
        private class DiagnosticSubscription : IDisposable
        {
            internal IObserver<KeyValuePair<string, object>> Observer;

            internal Predicate<string> IsEnabled;

            internal DiagnosticListener Owner;

            internal DiagnosticSubscription Next;

            public void Dispose()
            {
                DiagnosticSubscription subscriptions;
                DiagnosticSubscription value;
                do
                {
                    subscriptions = Owner._subscriptions;
                    value = Remove(subscriptions, this);
                }
                while (Interlocked.CompareExchange(ref Owner._subscriptions, value, subscriptions) != subscriptions);
            }

            private static DiagnosticSubscription Remove(DiagnosticSubscription subscriptions, DiagnosticSubscription subscription)
            {
                if (subscriptions == null)
                {
                    return null;
                }

                if (subscriptions.Observer == subscription.Observer && subscriptions.IsEnabled == subscription.IsEnabled)
                {
                    return subscriptions.Next;
                }

                return new DiagnosticSubscription
                {
                    Observer = subscriptions.Observer,
                    Owner = subscriptions.Owner,
                    IsEnabled = subscriptions.IsEnabled,
                    Next = Remove(subscriptions.Next, subscription)
                };
            }
        }

        //
        // 摘要:
        //     Logically AllListenerObservable has a very simple task. It has a linked list
        //     of subscribers that want a callback when a new listener gets created. When a
        //     new DiagnosticListener gets created it should call OnNewDiagnosticListener so
        //     that AllListenerObservable can forward it on to all the subscribers.
        private class AllListenerObservable : IObservable<DiagnosticListener>
        {
            //
            // 摘要:
            //     One node in the linked list of subscriptions that AllListenerObservable keeps.
            //     It is IDisposable, and when that is called it removes itself from the list.
            internal class AllListenerSubscription : IDisposable
            {
                private readonly AllListenerObservable _owner;

                internal readonly IObserver<DiagnosticListener> Subscriber;

                internal AllListenerSubscription Next;

                internal AllListenerSubscription(AllListenerObservable owner, IObserver<DiagnosticListener> subscriber, AllListenerSubscription next)
                {
                    _owner = owner;
                    Subscriber = subscriber;
                    Next = next;
                }

                public void Dispose()
                {
                    if (_owner.Remove(this))
                    {
                        Subscriber.OnCompleted();
                    }
                }
            }

            private AllListenerSubscription _subscriptions;

            public IDisposable Subscribe(IObserver<DiagnosticListener> observer)
            {
                lock (s_lock)
                {
                    for (DiagnosticListener diagnosticListener = s_allListeners; diagnosticListener != null; diagnosticListener = diagnosticListener._next)
                    {
                        observer.OnNext(diagnosticListener);
                    }

                    _subscriptions = new AllListenerSubscription(this, observer, _subscriptions);
                    return _subscriptions;
                }
            }

            //
            // 摘要:
            //     Called when a new DiagnosticListener gets created to tell anyone who subscribed
            //     that this happened.
            //
            // 参数:
            //   diagnosticListener:
            internal void OnNewDiagnosticListener(DiagnosticListener diagnosticListener)
            {
                for (AllListenerSubscription allListenerSubscription = _subscriptions; allListenerSubscription != null; allListenerSubscription = allListenerSubscription.Next)
                {
                    allListenerSubscription.Subscriber.OnNext(diagnosticListener);
                }
            }

            //
            // 摘要:
            //     Remove 'subscription from the list of subscriptions that the observable has.
            //     Called when subscriptions are disposed. Returns true if the subscription was
            //     removed.
            private bool Remove(AllListenerSubscription subscription)
            {
                lock (s_lock)
                {
                    if (_subscriptions == subscription)
                    {
                        _subscriptions = subscription.Next;
                        return true;
                    }

                    if (_subscriptions != null)
                    {
                        AllListenerSubscription allListenerSubscription = _subscriptions;
                        while (allListenerSubscription.Next != null)
                        {
                            if (allListenerSubscription.Next == subscription)
                            {
                                allListenerSubscription.Next = allListenerSubscription.Next.Next;
                                return true;
                            }

                            allListenerSubscription = allListenerSubscription.Next;
                        }
                    }

                    return false;
                }
            }
        }

        private volatile DiagnosticSubscription _subscriptions;

        private DiagnosticListener _next;

        private bool _disposed;

        private static DiagnosticListener s_allListeners;

        private static AllListenerObservable s_allListenerObservable;

        private static object s_lock = new object();

        //
        // 摘要:
        //     When you subscribe to this you get callbacks for all NotificationListeners in
        //     the appdomain as well as those that occurred in the past, and all future Listeners
        //     created in the future.
        public static IObservable<DiagnosticListener> AllListeners
        {
            get
            {
                if (s_allListenerObservable == null)
                {
                    s_allListenerObservable = new AllListenerObservable();
                }

                return s_allListenerObservable;
            }
        }

        //
        // 摘要:
        //     When a DiagnosticListener is created it is given a name. Return this.
        public string Name { get; private set; }

        //
        // 摘要:
        //     Add a subscriber (Observer). If 'IsEnabled' == null (or not present), then the
        //     Source's IsEnabled will always return true.
        public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Predicate<string> isEnabled)
        {
            if (_disposed)
            {
                return new DiagnosticSubscription
                {
                    Owner = this
                };
            }

            DiagnosticSubscription diagnosticSubscription = new DiagnosticSubscription
            {
                Observer = observer,
                IsEnabled = isEnabled,
                Owner = this,
                Next = _subscriptions
            };
            while (Interlocked.CompareExchange(ref _subscriptions, diagnosticSubscription, diagnosticSubscription.Next) != diagnosticSubscription.Next)
            {
                diagnosticSubscription.Next = _subscriptions;
            }

            return diagnosticSubscription;
        }

        //
        // 摘要:
        //     Same as other Subscribe overload where the predicate is assumed to always return
        //     true.
        public IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer)
        {
            return Subscribe(observer, null);
        }

        //
        // 摘要:
        //     Make a new DiagnosticListener, it is a NotificationSource, which means the returned
        //     result can be used to log notifications, but it also has a Subscribe method so
        //     notifications can be forwarded arbitrarily. Thus its job is to forward things
        //     from the producer to all the listeners (multi-casting). Generally you should
        //     not be making your own DiagnosticListener but use the DiagnosticListener.Default,
        //     so that notifications are as 'public' as possible.
        public DiagnosticListener(string name)
        {
            Name = name;
            lock (s_lock)
            {
                s_allListenerObservable?.OnNewDiagnosticListener(this);
                _next = s_allListeners;
                s_allListeners = this;
            }

            //DiagnosticSourceEventSource.Logger.IsEnabled();
        }

        //
        // 摘要:
        //     Clean up the NotificationListeners. Notification listeners do NOT DIE ON THEIR
        //     OWN because they are in a global list (for discoverability). You must dispose
        //     them explicitly. Note that we do not do the Dispose(bool) pattern because we
        //     frankly don't want to support subclasses that have non-managed state.
        public virtual void Dispose()
        {
            lock (s_lock)
            {
                if (_disposed)
                {
                    return;
                }

                _disposed = true;
                if (s_allListeners == this)
                {
                    s_allListeners = s_allListeners._next;
                }
                else
                {
                    for (DiagnosticListener next = s_allListeners; next != null; next = next._next)
                    {
                        if (next._next == this)
                        {
                            next._next = _next;
                            break;
                        }
                    }
                }

                _next = null;
            }

            DiagnosticSubscription location = null;
            Interlocked.Exchange(ref location, _subscriptions);
            while (location != null)
            {
                location.Observer.OnCompleted();
                location = location.Next;
            }
        }

        //
        // 摘要:
        //     Return the name for the ToString() to aid in debugging.
        public override string ToString()
        {
            return Name;
        }

        //
        // 摘要:
        //     Override abstract method
        public override bool IsEnabled(string name)
        {
            for (DiagnosticSubscription diagnosticSubscription = _subscriptions; diagnosticSubscription != null; diagnosticSubscription = diagnosticSubscription.Next)
            {
                if (diagnosticSubscription.IsEnabled == null || diagnosticSubscription.IsEnabled(name))
                {
                    return true;
                }
            }

            return false;
        }

        //
        // 摘要:
        //     Override abstract method
        public override void Write(string name, object value)
        {
            for (DiagnosticSubscription diagnosticSubscription = _subscriptions; diagnosticSubscription != null; diagnosticSubscription = diagnosticSubscription.Next)
            {
                diagnosticSubscription.Observer.OnNext(new KeyValuePair<string, object>(name, value));
            }
        }
    }
}
#endif
